﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using Lucene.Net.Documents;
using PsiIndexer;

namespace PsiIndexerGUI {
  public class MainViewModel : INotifyPropertyChanged {
    private readonly PsiIndexer.PsiIndexer psiIndexer;
    private ObservableCollection<PsiChatSearchResult> results;

    private string searchTerm;

    public MainViewModel(PsiIndexer.PsiIndexer psiIndexer) {
      this.psiIndexer = psiIndexer;
    }

    public string SearchTerm {
      get { return this.searchTerm; }
      set {
        if (this.searchTerm == value) {
          return;
        }
        this.searchTerm = value;
        this.DoSearch();
        this.OnPropertyChange("SearchTerm");
      }
    }

    public ObservableCollection<PsiChatSearchResult> Results {
      get { return this.results; }
      set {
        if (this.results == value) {
          return;
        }
        this.results = value;
        this.OnPropertyChange("Results");
      }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    private void DoSearch() {
      if (!string.IsNullOrEmpty(this.searchTerm)) {
        SearchResult searchResult = this.psiIndexer.Search(this.searchTerm);
        if (searchResult.Success) {
          this.Results = new ObservableCollection<PsiChatSearchResult>(searchResult.Hits.Select(hit => PsiChatSearchResult.Create(this.psiIndexer, hit, 10)));
        }
      }
      else {
        this.Results = new ObservableCollection<PsiChatSearchResult>();
      }
    }

    private void OnPropertyChange(string propertyName) {
      PropertyChangedEventHandler tmp = this.PropertyChanged;
      if (tmp != null) {
        tmp(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }

  public class PsiChatSearchResult {
    private PsiChatSearchResult() {}

    public ObservableCollection<PsiChatInfo> SurroundingChats { get; set; }

    public PsiChatInfo Chat { get; set; }

    public static PsiChatSearchResult Create(PsiIndexer.PsiIndexer pi, Document d, int howManySurrounders) {
      var ret = new PsiChatSearchResult();
      ret.Chat = pi.GetChat(d.Get(LuceneMagicStrings.ID));
      ret.SurroundingChats = getSurroundingChats(ret.Chat, howManySurrounders);
      return ret;
    }

    private static ObservableCollection<PsiChatInfo> getSurroundingChats(PsiChatInfo chat, int howMany) {
      var tmpList = new List<PsiChatInfo>();
      PsiChatInfo tmp = chat;
      // add some backward
      for (int i = 0; i < howMany; i++) {
        PsiChatInfo prevChat = tmp.PrevChat;
        if (prevChat != null) {
          tmpList.Add(prevChat);
          tmp = prevChat;
        }
        else {
          break;
        }
      }

      // add the chat itself
      tmpList.Add(chat);

      tmp = chat;
      // add some forward
      for (int i = 0; i < howMany; i++) {
        PsiChatInfo nextChat = tmp.NextChat;
        if (nextChat != null) {
          tmpList.Add(nextChat);
          tmp = nextChat;
        }
        else {
          break;
        }
      }
      return new ObservableCollection<PsiChatInfo>(tmpList.OrderBy(pci => pci.Time));
    }

    public override string ToString()
    {
      return string.Format("{0}: {1}", Chat.Conversation.Author, Chat.Text);
    }
  }
}